#define PCRE2_CODE_UNIT_WIDTH 8

#include<stdio.h>
#include<stdlib.h>

#include <pcre2.h>

// 输出宏
#define PRINT_INT(n) printf(#n " = %d\n", n)
#define PRINT_LD(n) printf(#n " = %ld\n", n)
#define PRINT_STR(s) printf(#s " = %s\n", s)

int main()
{
    char ver_buf[256] = {0};
    // 字义正则表达式
    PCRE2_SPTR pattern = (PCRE2_SPTR)"hell(\\w)";
    // 定义输入字符串
    PCRE2_SPTR input = (PCRE2_SPTR)"hellp hello world, PCRE2!";

    pcre2_code *re;
    int errorcode;
    PCRE2_SIZE erroroffset;
    PCRE2_UCHAR buffer[256];
    pcre2_match_data *match_data;

    pcre2_config(PCRE2_CONFIG_UNICODE_VERSION, ver_buf);

    PRINT_STR(ver_buf);

    // 编译正则表达式
    re = pcre2_compile(pattern,               // 匹配模式(正则表达式)
                       PCRE2_ZERO_TERMINATED, // 模式长度(以'\0'结尾)
                       0,                     // 选项
                       &errorcode,            // 错误代码
                       &erroroffset,          // 错误偏移量
                       NULL                   // 上下文，一般取NULL
                       );
    if(re == NULL)
    {
        pcre2_get_error_message(errorcode, buffer, sizeof(buffer));
        printf("PCRE2 compilation failed at offset %d: %s\n",
                (int)erroroffset,  buffer);
        exit(EXIT_FAILURE);
    }

    // 构造匹配寄存器以记录匹配结果
    match_data = pcre2_match_data_create_from_pattern(re, NULL);

    // 匹配
    int rc = pcre2_match(re,                    // 正则缓存(编译结果)
                         input,                 // 待匹配字符串
                         PCRE2_ZERO_TERMINATED, // 待匹配字符串长度('\0'结尾)
                         0,                     // 开始匹配偏移量
                         0,                     // 选项
                         match_data,            // 匹配寄存器
                         NULL                   // 上下文，一般取NULL
                         );
    if(rc < 0)
    {
        switch(rc)
        {
            case PCRE2_ERROR_NOMATCH: printf("No match\n"); break;
            // TODO: 可以添加其它错误处理代码
            default: printf("Matching error %d\n", rc); break;
        }
        // 释放内存
        pcre2_match_data_free(match_data);
        pcre2_code_free(re);
        exit(EXIT_FAILURE);
    }

    // 得到匹配结果向量(按开始结束的方式记录各分组匹配结果，0表示group 0)
    PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);

    PRINT_INT(rc);

    // 输出匹配结果
    while(rc > 0)
    {
        printf("Match: \n");
        PCRE2_SPTR substring_start;
        PCRE2_SIZE substring_length;

        for(int i = 0; i < rc; i++)
        {
            // 匹配开始和结束位置的差值，
            // 得到匹配的字符个数
            substring_start = input + ovector[2 * i];
            substring_length = ovector[2 * i + 1] - ovector[2 * i];

            PRINT_LD(ovector[2 * i]);
            PRINT_LD(ovector[2 * i + 1]);
            printf("%2d: %.*s\n", i, (int)substring_length, 
                                  (char*)substring_start);
        }

        // 从上次匹配末尾再次开始匹配(或用input += ovector[1];)
        input = substring_start + substring_length;
        rc = pcre2_match(re, input, PCRE2_ZERO_TERMINATED, 
                         0, 0, match_data, NULL);

        // 获取匹配寄存器
        ovector = pcre2_get_ovector_pointer(match_data);
    }

    // 释放内存
    pcre2_match_data_free(match_data);
    pcre2_code_free(re);

    return 0;
}
